﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Maman18
{
    public class BoxesWorkshop
    {
        // This tree will be order by Side and the inside Tree by Height
        private RedBlackTree<int, RedBlackTree<int,int>> straight_Tree { get; set; }

        // This tree will be order by height and the inside Tree by side
        public RedBlackTree<int, RedBlackTree<int, int>> reversed_Tree { get; set; }
 
        public BoxesWorkshop()
        {
            this.straight_Tree = new RedBlackTree<int,RedBlackTree<int,int>>();
            this.reversed_Tree = new RedBlackTree<int,RedBlackTree<int,int>>();
        }

        public void InsertBox(int side, int height)
        {
            //First Part on Side Tree

            // Check if There a Box With this Side
            if (this.straight_Tree.IsExists(side))
            {
                //Check if There is same box
                if (!this.straight_Tree.SearchNode(side).Value.IsExists(height))
                {
                    this.straight_Tree.SearchNode(side).Value.Insert(height, 1);
                }
                else
                {
                    this.straight_Tree.SearchNode(side).Value.SearchNode(height, SearchOptions.Exact).Value++;
                }
            }
            else 
            {
                RedBlackTree<int, int> temp = new RedBlackTree<int, int>();
                temp.Insert(height,1);
                this.straight_Tree.Insert(side, temp);
            }

            //Second Part on height Tree

            // Check if There a Box With this height
            if (this.reversed_Tree.IsExists(height))
            {
                //Check if There is same box
                if (!this.reversed_Tree.SearchNode(height).Value.IsExists(side))
                {
                    this.reversed_Tree.SearchNode(height).Value.Insert(side, 1);
                }
                else 
                {
                    this.reversed_Tree.SearchNode(height).Value.SearchNode(side, SearchOptions.Exact).Value++;
                }
            }
            else
            {
                RedBlackTree<int, int> temp = new RedBlackTree<int, int>();
                temp.Insert(side, 1);
                this.reversed_Tree.Insert(height, temp);
            }
        }

        public void RemoveBox(int side, int height)
        {
            // Delete From The Inside Tree
            if ((this.straight_Tree.SearchNode(side)).Value.SearchNode(height).Value > 1)
            {
                (this.straight_Tree.SearchNode(side)).Value.SearchNode(height).Value--;
            }
            else
            {
                (this.straight_Tree.SearchNode(side)).Value.Delete((this.straight_Tree.SearchNode(side)).Value.SearchNode(height));
            }

            //Check id This is The Last Box With This side
            if (this.straight_Tree.SearchNode(side).Value.IsEmpty)
            {
                this.straight_Tree.Delete(this.straight_Tree.SearchNode(side));
            }

            // Delete From The Inside Tree 
            if ((this.reversed_Tree.SearchNode(height)).Value.SearchNode(side).Value > 1)
            {
                (this.reversed_Tree.SearchNode(height)).Value.SearchNode(side).Value--;
            }
            else
            {
                (this.reversed_Tree.SearchNode(height)).Value.Delete((this.reversed_Tree.SearchNode(height)).Value.SearchNode(side));
            }

            //Check id This is The Last Box With This Height
            if (this.reversed_Tree.SearchNode(height).Value.IsEmpty)
            {
                this.reversed_Tree.Delete(this.reversed_Tree.SearchNode(height));
            }
        }

        public Box GetBox(int side, int height)
        {
            RedBlackTree<int, RedBlackTree<int, int>>.RedBlackNode CurrentNode;
            Box Minimal_Box = null;
            Box Temp_Box = new Box();

            // Check which tree to search
            if (this.reversed_Tree.Size > this.straight_Tree.Size)
            {
                CurrentNode = this.straight_Tree.SearchNode(side, SearchOptions.Larger);

                // Check all The Tree
                while (CurrentNode != RedBlackTree<int, RedBlackTree<int, int>>.NullNode)
                {
                    // Check if there is a side
                    if (CurrentNode.Value.SearchNode(height, SearchOptions.Larger) != (RedBlackTree<int, int>.NullNode))
                    { 
                        Temp_Box.Side = CurrentNode.Key;
                        Temp_Box.Height = CurrentNode.Value.SearchNode(height, SearchOptions.Larger).Key;

                        // in the first time init minimal
                        if (Minimal_Box == null)
                        {
                            Minimal_Box = Temp_Box;
                        }

                        // Check for smallest
                        if (Temp_Box.Volume < Minimal_Box.Volume)
                        {
                            Minimal_Box = Temp_Box;
                        }
                    }

                    CurrentNode = CurrentNode.Successor();
                }
            }
            // The second part because we couldn't know which key is side or height if we would do it in one loop
            else 
            {
                CurrentNode = this.reversed_Tree.SearchNode(height, SearchOptions.Larger);

                // Runs all over the tree
                while (CurrentNode != RedBlackTree<int,RedBlackTree<int,int>>.NullNode)
                {
                    // Check if there is a side
                    if ((CurrentNode.Value.SearchNode(side, SearchOptions.Larger)) != (RedBlackTree<int, int>.NullNode))
                    {
                        Temp_Box.Height = CurrentNode.Key;
                        Temp_Box.Side = CurrentNode.Value.SearchNode(side, SearchOptions.Larger).Key;

                        // in the first time init minimal
                        if (Minimal_Box == null)
                        {
                            Minimal_Box = Temp_Box;
                        }

                        // Check For minimal
                        if (Temp_Box.Volume < Minimal_Box.Volume)
                        {
                            Minimal_Box = Temp_Box;
                        }
                    }

                    CurrentNode = CurrentNode.Successor();
                }
            }
           
            return (Minimal_Box);
        }

        /// <summary>
        /// Check if there is a proper box
        /// </summary>
        /// <param name="side"></param>
        /// <param name="height"></param>
        /// <returns></returns>
        public bool CheckBox(int side, int height)
        {
            // Check if there is a proper box
            if ((this.GetBox(side,height)) != null)
            {   
                return true;
            }

            return false;
        }
    }
}
